package com.camel.iamhi.service.impl;

import cn.hutool.core.util.StrUtil;
import com.camel.iamhi.base.BaseModel;
import com.camel.iamhi.base.Page;
import com.camel.iamhi.entities.IFilter;
import com.camel.iamhi.entities.IParams;
import com.camel.iamhi.enums.EntityStatus;
import com.camel.iamhi.service.BaseService;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.springframework.data.jpa.repository.JpaRepository;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public abstract class AbstractBaseService<T extends BaseModel> implements BaseService<T> {

    private Class<T> genericType;

    public AbstractBaseService() {
        // 获取泛型类型
        this.genericType = resolveGenericType();
    }

    // 解析泛型类型的核心方法
    @SuppressWarnings("unchecked")
    private Class<T> resolveGenericType() {
        // 1. 获取父类的带泛型类型（如 BaseService<String>）
        Type genericSuperclass = this.getClass().getGenericSuperclass();

        // 2. 判断父类是否为参数化类型（即是否明确指定了泛型）
        if (!(genericSuperclass instanceof ParameterizedType)) {
            // 若子类未明确指定泛型（如 class Son<T> extends BaseService<T>），则无法获取具体类型
            throw new RuntimeException("父类泛型未指定具体类型，请在子类中明确泛型参数");
        }
        // 3. 提取泛型参数的实际类型（如 String）
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        // 4. 校验并返回泛型类型（假设父类只有一个泛型参数 T）
        if (actualTypeArguments.length == 0) {
            throw new RuntimeException("父类未定义泛型参数");
        }
        // 将 Type 转换为 Class（泛型擦除后实际为 Class 类型）
        return (Class<T>) actualTypeArguments[0];
    }

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<T> selectList(IParams params) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        // 列表
        CriteriaQuery<T> query = cb.createQuery(genericType);
        Root<T> root = query.from(genericType);
        List<Predicate> predicates = predicateFromFilters(cb, params.getFilters(), root);
        query.where(cb.and(predicates.toArray(new Predicate[0])));
        if (StrUtil.isNotBlank(params.getOrderBy())) {
            query.orderBy(cb.desc(root.get(params.getOrderBy())));
        } else {
            query.orderBy(cb.desc(root.get("id")));
        }
        return entityManager.createQuery(query).getResultList();
    }

    @Override
    public Page<T> page(IParams params) {
        int size = params.getPageSize();
        int page = params.getPage();

        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaBuilder countCb = entityManager.getCriteriaBuilder();
        // 列表
        CriteriaQuery<T> query = cb.createQuery(genericType);
        Root<T> root = query.from(genericType);
        // 计数
        CriteriaQuery<Long> countQuery = countCb.createQuery(Long.class);
        Root<T> countRoot = countQuery.from(genericType);
        // -------------------------- 1. 构建查询条件（复用逻辑，而非对象） --------------------------
        List<Predicate> predicates = predicateFromFilters(cb, params.getFilters(), root);
        List<Predicate> countPredicates = predicateFromFilters(cb, params.getFilters(), countRoot);

        query.where(cb.and(predicates.toArray(new Predicate[0])));
        countQuery.where(cb.and(countPredicates.toArray(new Predicate[0])));

        // 排序
        query.orderBy(cb.desc(root.get("id")));

        // 分页参数
        int offset = (page - 1) * size;
        List<T> userList = entityManager.createQuery(query)
                .setFirstResult(offset)
                .setMaxResults(size)
                .getResultList();

        // 计数
        countQuery.select(cb.count(countRoot));
        Long total = entityManager.createQuery(countQuery).getSingleResult();

        // 6. 封装分页结果
        Page<T> res = new Page<>();
        res.setList(userList);
        res.setPage(params.getPage());
        res.setTotal(total.intValue());
        return res;
    }

    @Override
    public T save(T entity) {
        return getRepository().save(entity);
    }

    @Override
    public void delete(Long id) {
        T entity = getRepository().findById(id).orElseThrow();
        entity.setUpdateAt(new Date());
        entity.setStatus(EntityStatus.INVALID.getCode());
        getRepository().save(entity);
    }

    abstract JpaRepository<T, Long> getRepository();


    /**
     * 通过Filter获取查询条件
     *
     * @param filters 过滤条件
     * @param cb      条件
     * @return
     */
    public List<Predicate> predicateFromFilters(CriteriaBuilder cb, List<IFilter> filters, Root<T> root) {
        List<Predicate> predicates = new ArrayList<>();

        for (IFilter filter : filters) {
            switch (filter.getCompare().toUpperCase()) {
                case "LIKE":
                    predicates.add(cb.like(root.get(filter.getFieldName()), "%" + filter.getFieldValue() + "%"));
                    break;
                case "=":
                    predicates.add(cb.equal(root.get(filter.getFieldName()), filter.getFieldValue()));
                    break;
            }
        }
        predicates.add(cb.equal(root.get("status"), EntityStatus.NORMAL.getCode()));

        return predicates;
    }
}
